Améliorez votre JS grâce à la puissance de la programmation fonctionnelle !

David Sferruzza

À propos de moi

Découverte de la programmation fonctionnelle

C'est un paradigme différent de la programmation impérative "classique", ce qui implique :

Intérêt ?

La promesse

Apprendre Haskell permet d'écrire de meilleurs programmes, même dans d'autres langages.

C'est ce qui s'est passé pour moi \o/

On va voir quelques concepts de FP qui peuvent s'appliquer à JavaScript, et comment ça améliore le code !

Fonction impure

function diviserParDeux(nombre) {
    var missile = lancerUnMissileNucleaire();
    fairePorterLeChapeauAuDrManhattan(missile);
    return nombre / 2;
}

Cette fonction a des effets de bord observables qu'on ne peut pas deviner en regardant sa valeur de retour. Il faut donc faire constamment attention lorsqu'on la manipule !

Fonction pure

function ajouterCinq(nombre) {
    return nombre + 5;
}

Cette fonction n'a pas d'effets de bord. Elle renvoie toujours le même résultat lorsqu'on l'appelle avec les mêmes arguments.

ajouterCinq(-4) == ajouterCinq(-4)

Transparence référentielle

Le résultat du programme ne change pas si on remplace une expression par une expression de valeur équivalente.

Utiliser des fonctions pures permet de résonner sur son programme comme sur une équation.

Recommandations

Construire son programme avec un maximum de fonctions pures

La logique métier est fiable, sans surprise et aisément testable.

Isoler les fonctions qui ont des effets de bord

On sait quelles fonctions ont des effets de bord, ce qui permet d’être prudent lorsqu’on les manipule.

Fonction d'ordre supérieur

En JS, les fonctions sont des objets de première classe (first-class citizen).

Une fonction d’ordre supérieur est une fonction qui possède au moins l'une des propriétés suivantes :

Exemple de fonction d'ordre supérieur

function appliquerDeuxFois(f, x) {
    return f(f(x));
}
// ^ accepte une fonction en paramètre

function foisTrois(x) {
    return x * 3;
}

appliquerDeuxFois(foisTrois, 7);
// --> (7 * 3) * 3 = 63

Intérêt des fonctions d'ordre supérieur

On va voir un exemple concret : les opérations sur les tableaux en JS.

Situation

var villes = [
    { nom: "Nantes", dep: 44, mer: false },
    { nom: "Dunkerque", dep: 59, mer: true },
    { nom: "Paris", dep: 75, mer: false },
];

On veut obtenir une liste de chaines de type ville (dep).

On va écrire une fonction rendreVillesAffichables telle que :

rendreVillesAffichables(villes);
// --> ["Nantes (44)", "Dunkerque (59)",
//      "Paris (75)"]

Solution impérative

function rendreVillesAffichables(villes) {
    for (var i = 0; i < villes.length; i++) {
        villes[i] = villes[i].nom +
                    " (" + villes[i].dep + ")";
    }
    return villes;
}

On mélange 2 comportements :

Array.map

function rendreVillesAffichables(villes) {
    function transformation(ville) {
        return ville.nom +
                " (" + ville.dep + ")";
    }
    return villes.map(transformation);
}

Array.filter

villes.filter(function(item) {
    // Si la ville est près de la mer,
    // on renvoie true, sinon false
    return item.mer;
});
// --> [ { nom: "Dunkerque", dep: 59,
//          mer: true } 

Chainons !

villes.filter(function(item) {
    return !item.mer;
}).map(function(item) {
    return item.nom + " (" + item.dep + ")";
});
// --> ["Nantes (44)", "Paris (75)"]

Rappel : Array.map et Array.filter sont des fonctions d'ordre supérieur.

Array.reduce

var personnes = [
    { nom: "Bruce", age: 30 },
    { nom: "Tony", age: 35 },
    { nom: "Peter", age: 26 },
];

personnes.reduce(function(acc, cur) {
    return acc + cur.age;
}, 0);
// --> 91

Array.reduce

function map(tableau, transformation) {
    return tableau.reduce(function(acc, cur) {
        acc.push(transformation(cur));
        return acc;
    }, []);
}

function filter(tableau, predicat) {
    return tableau.reduce(function(acc, cur) {
        if (predicat(cur)) acc.push(cur);
        return acc;
    }, []);
}

Antisèche

Si vous avez un tableau et que vous voulez :

Conclusion

La programmation fonctionnelle offre de belles manières d'écrire des programmes fiables et maintenables.

Ressources

Questions ?

Twitter : @d_sferruzza

Slides sur GitHub :

dsferruzza/talk-programmation-fonctionnelle-en-js